package com.bxmdm.ragdemo;

import com.bxmdm.ragdemo.reader.EnglishQAReader;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 问题向量化效果对比测试
 * 比较使用加权计算和直接向量化的效果
 */
@SpringBootTest
public class VectorizedQuestionsComparisonTest {

    @Autowired
    private VectorStore vectorStore;

    @Autowired
    private EmbeddingClient embeddingClient;

    // 日志文件夹路径
    private final String LOG_DIR = "src/test/logs";

    // 存储查询的向量表示
    private Map<String, List<Double>> queryEmbeddingsCache = new HashMap<>(); // 测试查询列表 - 基于样本数据调整，涵盖英语语法问题
    private final List<String> testQueries = Arrays.asList(
            // 原有的查询
            "When do I use can or could?",
            "What is the difference between can and could?",
            "Where does quint in quintessential come from?",
            "When should I use shall versus will?",
            "When did while and whilst become interchangeable?",
            "What's the difference between may and might?",
            "Is it appropriate to use short form of have?",
            "Which words in a title should be capitalized?",
            "When is it appropriate to end a sentence in a preposition?",

            "Where did the term OK come from?",
            "What is the proper plural of freshman?",
            "Where did the singular innings come from?",
            "Are betwixt and trebble acceptable in American English?",
            "Is it acceptable for a period to come after a quote?",
            "What's wrong with this question versus in this question?",
            "Is there a correct gender-neutral singular pronoun?",
            "Can a word be contracted twice like I'ven't?",
            "What's the rule for using who and whom correctly?",
            "How do I ask a question politely with may versus can?",
            "What's the difference between a gerund and a participle?",
            "When to use that and when to use which in clauses?");

    // 存储查询到文档问题的映射
    private Map<String, List<String>> queryToDocumentMap = new HashMap<>();

    @Test
    public void compareWeightedVsDirectVectorization() throws IOException {
        // 创建日志目录
        Path logDir = Paths.get(LOG_DIR);
        if (!Files.exists(logDir)) {
            Files.createDirectories(logDir);
        }

        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
        String logFileName = LOG_DIR + "/question_vectorization_test_" + timestamp + ".log";

        try (PrintWriter logWriter = new PrintWriter(logFileName, StandardCharsets.UTF_8)) {
            logWriter.println("======= 加权向量化问题 vs 直接向量化问题效果对比测试 =======");
            logWriter.println("测试时间: " + LocalDateTime.now());
            logWriter.println("使用数据: converted_data_sample.json");
            System.out.println("======= 加权向量化问题 vs 直接向量化问题效果对比测试 =======");
            System.out.println("日志文件: " + logFileName);

            // 使用样本数据
            Resource resource = new ClassPathResource("converted_data_sample.json");
            if (!resource.exists()) {
                String errorMsg = "样本数据文件不存在，无法进行测试";
                System.out.println(errorMsg);
                logWriter.println(errorMsg);
                return;
            }

            // 创建两种版本的Reader
            EnglishQAReader weightedReader = new EnglishQAReader(resource, embeddingClient);
            DirectQuestionVectorizer directReader = new DirectQuestionVectorizer(resource, embeddingClient);

            // 分别导入数据
            logWriter.println("\n=== 导入加权向量化问题数据 ===");
            System.out.println("\n=== 导入加权向量化问题数据 ===");
            List<Document> weightedDocs = weightedReader.get();
            logWriter.println("加权向量化问题文档数量: " + weightedDocs.size());
            System.out.println("加权向量化问题文档数量: " + weightedDocs.size());

            logWriter.println("\n=== 导入直接向量化问题数据 ===");
            System.out.println("\n=== 导入直接向量化问题数据 ===");
            List<Document> directDocs = directReader.get();
            logWriter.println("直接向量化问题文档数量: " + directDocs.size());
            System.out.println("直接向量化问题文档数量: " + directDocs.size());

            // 为两个版本的文档添加标识
            weightedDocs.forEach(doc -> doc.getMetadata().put("version", "weighted"));
            directDocs.forEach(doc -> doc.getMetadata().put("version", "direct"));

            // 合并并导入到向量库
            List<Document> allDocs = new ArrayList<>();
            allDocs.addAll(weightedDocs);
            allDocs.addAll(directDocs);
            vectorStore.add(allDocs);

            logWriter.println("总文档数量: " + allDocs.size());
            System.out.println("总文档数量: " + allDocs.size());

            // 初始化查询映射
            initializeQueryMapping(resource);

            // 执行对比测试
            performComparison(logWriter);

            logWriter.println("\n测试完成时间: " + LocalDateTime.now());
            System.out.println("测试完成，详细结果已保存到: " + logFileName);
        }
    }

    private void performComparison(PrintWriter logWriter) {
        String header = "\n======= 开始对比测试 =======";
        System.out.println(header);
        logWriter.println(header);

        Map<String, Double> weightedScores = new HashMap<>();
        Map<String, Double> directScores = new HashMap<>();

        for (int i = 0; i < testQueries.size(); i++) {
            String query = testQueries.get(i);
            String queryHeader = "\n--- 测试查询 " + (i + 1) + " ---";
            String queryLine = "Query: " + query;

            System.out.println(queryHeader);
            System.out.println(queryLine);
            logWriter.println(queryHeader);
            logWriter.println(queryLine);

            // 搜索加权向量化版本
            List<Document> weightedResults = searchByVersion(query, "weighted", 5, logWriter);
            double weightedScore = evaluateResults(query, weightedResults, logWriter, "加权向量化");
            weightedScores.put(query, weightedScore);

            // 搜索直接向量化版本
            List<Document> directResults = searchByVersion(query, "direct", 5, logWriter);
            double directScore = evaluateResults(query, directResults, logWriter, "直接向量化");
            directScores.put(query, directScore);

            String weightedResult = "加权向量化平均分: " + String.format("%.3f", weightedScore);
            String directResult = "直接向量化平均分: " + String.format("%.3f", directScore);
            String diffResult = "差异: " + String.format("%.3f", weightedScore - directScore);

            System.out.println(weightedResult);
            System.out.println(directResult);
            System.out.println(diffResult);
            logWriter.println(weightedResult);
            logWriter.println(directResult);
            logWriter.println(diffResult);
        }

        // 计算总体统计
        double avgWeightedScore = weightedScores.values().stream().mapToDouble(Double::doubleValue).average()
                .orElse(0.0);
        double avgDirectScore = directScores.values().stream().mapToDouble(Double::doubleValue).average()
                .orElse(0.0);

        String overallHeader = "\n======= 总体结果 =======";
        String avgWeightedResult = "加权向量化平均分: " + String.format("%.3f", avgWeightedScore);
        String avgDirectResult = "直接向量化平均分: " + String.format("%.3f", avgDirectScore);
        String improvement = "性能提升: " + String.format("%.3f", avgWeightedScore - avgDirectScore);
        String improvementPercent = "提升百分比: "
                + String.format("%.1f%%", (avgWeightedScore - avgDirectScore) / avgDirectScore * 100);

        System.out.println(overallHeader);
        System.out.println(avgWeightedResult);
        System.out.println(avgDirectResult);
        System.out.println(improvement);
        System.out.println(improvementPercent);

        logWriter.println(overallHeader);
        logWriter.println(avgWeightedResult);
        logWriter.println(avgDirectResult);
        logWriter.println(improvement);
        logWriter.println(improvementPercent);

        // 详细分析
        analyzeDetailedResults(weightedScores, directScores, logWriter);
    }

    private List<Document> searchByVersion(String query, String version, int topK, PrintWriter logWriter) {
        // 获取所有搜索结果
        List<Document> allResults = vectorStore.similaritySearch(SearchRequest.query(query).withTopK(topK * 2));

        // 过滤指定版本的结果
        List<Document> filteredResults = allResults.stream()
                .filter(doc -> version.equals(doc.getMetadata().get("version")))
                .limit(topK)
                .collect(Collectors.toList());

        String resultMsg = version + " 版本返回结果数: " + filteredResults.size();
        System.out.println(resultMsg);
        logWriter.println(resultMsg);
        return filteredResults;
    }

    /**
     * 评估搜索结果质量
     * 返回一个0-1之间的分数，分数越高表示结果越相关
     */
    private double evaluateResults(String query, List<Document> results, PrintWriter logWriter, String versionName) {
        if (results.isEmpty()) {
            return 0.0;
        }

        // 获取查询的向量表示
        List<Double> queryEmbedding = getQueryEmbedding(query);

        // 获取与当前查询相关的文档问题
        List<String> relevantQuestions = queryToDocumentMap.getOrDefault(query, new ArrayList<>());
        boolean hasMappedQuestions = !relevantQuestions.isEmpty();

        double totalScore = 0.0;
        for (int i = 0; i < results.size(); i++) {
            Document doc = results.get(i);
            Map<String, Object> metadata = doc.getMetadata();

            // 获取完整问题和主要问题
            String fullQuestion = (String) metadata.getOrDefault("question", doc.getContent());
            String mainQuestion = (String) metadata.getOrDefault("main_question",
                    fullQuestion.split("\\r?\\n")[0].trim());

            // 计算向量相似度
            @SuppressWarnings("unchecked")
            List<Double> docEmbedding = (List<Double>) metadata.getOrDefault("embedding", new ArrayList<>());
            double vectorSimilarity = calculateCosineSimilarity(queryEmbedding, docEmbedding);

            double relevanceScore;

            // 如果有预定义的映射关系，则优先使用
            if (hasMappedQuestions) {
                // 检查当前结果是否在映射列表中
                boolean isExactMatch = relevantQuestions.contains(fullQuestion);
                if (isExactMatch) {
                    // 如果是精确匹配，基于向量相似度给予高分
                    // 但不直接给1.0，而是将向量相似度也纳入考量
                    relevanceScore = 0.7 + (vectorSimilarity * 0.3);
                } else {
                    // 仍然计算文本相似度，但增加向量相似度的权重
                    double mainQuestionScore = calculateRelevanceScore(query, mainQuestion);
                    double fullQuestionScore = calculateRelevanceScore(query, fullQuestion);

                    // 计算与映射问题的最高相似度
                    double mappedQuestionScore = 0.0;
                    for (String mappedQuestion : relevantQuestions) {
                        double similarity = calculateRelevanceScore(mappedQuestion, fullQuestion);
                        mappedQuestionScore = Math.max(mappedQuestionScore, similarity);
                    }

                    // 综合评分，加入向量相似度和映射相似度的因素
                    relevanceScore = mainQuestionScore * 0.3 + fullQuestionScore * 0.2 +
                            mappedQuestionScore * 0.2 + vectorSimilarity * 0.3;
                }
            } else {
                // 如果没有映射关系，结合文本相似度和向量相似度
                double mainQuestionScore = calculateRelevanceScore(query, mainQuestion);
                double fullQuestionScore = calculateRelevanceScore(query, fullQuestion);
                relevanceScore = mainQuestionScore * 0.4 + fullQuestionScore * 0.2 + vectorSimilarity * 0.4;
            }

            // 位置权重：排名越靠前权重越高
            double positionWeight = 1.0 / (i + 1);

            double weightedScore = relevanceScore * positionWeight;
            totalScore += weightedScore;

            // 添加映射信息和向量相似度到结果输出
            String mappingInfo = hasMappedQuestions ? (relevantQuestions.contains(fullQuestion) ? " [精确匹配]" : "") : "";
            String vectorInfo = " [向量相似度=" + String.format("%.3f", vectorSimilarity) + "]";

            String resultDetail = "  " + versionName + " 结果 " + (i + 1) + ": [分数="
                    + String.format("%.3f", relevanceScore) +
                    ", 位置权重=" + String.format("%.3f", positionWeight) + "]" +
                    mappingInfo + vectorInfo + " " +
                    mainQuestion + "\n    " +
                    fullQuestion.substring(0, Math.min(80, fullQuestion.length())) + "...";
            System.out.println(resultDetail);
            logWriter.println(resultDetail);
        }

        // 归一化分数
        double maxPossibleScore = 0.0;
        for (int i = 0; i < results.size(); i++) {
            maxPossibleScore += 1.0 / (i + 1); // 假设所有结果都是完美匹配
        }

        return maxPossibleScore > 0 ? totalScore / maxPossibleScore : 0.0;
    }

    /**
     * 计算查询和问题之间的相关性分数 - 改进版
     * 更加重视关键词匹配和语义相关性
     */
    private double calculateRelevanceScore(String query, String question) {
        String queryLower = query.toLowerCase().trim();
        String questionLower = question.toLowerCase().trim();

        // 1. 完全匹配
        if (queryLower.equals(questionLower)) {
            return 1.0;
        }

        // 2. 主要关键词精确匹配
        // 提取查询中的主要名词和动词，检查是否在问题中出现
        String[] querySentences = queryLower.split("[.!?]");
        String mainQuerySentence = querySentences[0].trim();

        // 对于问题是否包含整个查询句子给予很高的权重
        if (questionLower.contains(mainQuerySentence)) {
            return 0.9;
        }

        // 3. 包含关系
        if (questionLower.contains(queryLower) || queryLower.contains(questionLower)) {
            return 0.8;
        }

        // 4. 扩展词汇重叠度计算 - 考虑短语匹配
        // 分词处理
        Set<String> queryWords = new HashSet<>(Arrays.asList(queryLower.split("\\s+")));
        Set<String> questionWords = new HashSet<>(Arrays.asList(questionLower.split("\\s+")));

        // 移除停用词
        Set<String> stopWords = Set.of("the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for", "of",
                "with", "by", "is", "are", "was", "were", "be", "been", "have", "has", "had", "do", "does", "did",
                "will", "would", "could", "should", "may", "might", "can");
        queryWords.removeAll(stopWords);
        questionWords.removeAll(stopWords);

        Set<String> intersection = new HashSet<>(queryWords);
        intersection.retainAll(questionWords);

        Set<String> union = new HashSet<>(queryWords);
        union.addAll(questionWords);

        if (union.isEmpty()) {
            return 0.0;
        }

        // 基础Jaccard相似度
        double jaccardSimilarity = (double) intersection.size() / union.size();

        // 5. 提高共享关键词的权重
        // 特别重要的关键词，如"difference", "between", "usage" 等
        String[] importantKeywords = { "difference", "between", "usage", "use", "when", "how", "versus", "vs" };
        double keywordBonus = 0.0;
        for (String keyword : importantKeywords) {
            if (queryLower.contains(keyword) && questionLower.contains(keyword)) {
                keywordBonus += 0.15; // 显著提高匹配度
            }
        }

        // 6. 关键概念匹配（加分项）
        double conceptBonus = calculateConceptBonus(queryLower, questionLower);

        // 7. 合并所有分数，并确保不超过1.0
        return Math.min(1.0, jaccardSimilarity + keywordBonus + conceptBonus);
    }

    /**
     * 计算概念匹配加分 - 改进版
     * 针对英语语法问题更加精细的概念匹配
     */
    private double calculateConceptBonus(String query, String question) {
        // 1. 语法概念
        String[] grammarConcepts = {
                "tense", "verb", "modal", "article", "preposition", "conditional", "passive",
                "question", "grammar", "singular", "plural", "past", "present", "future",
                "continuous", "perfect", "imperative", "subjunctive", "participle"
        };

        // 2. 用法概念
        String[] usageConcepts = {
                "difference", "between", "when", "how", "use", "mean", "vs", "versus",
                "appropriate", "correct", "formal", "informal", "spoken", "written",
                "british", "american", "context", "proper"
        };

        // 3. 特定语法结构
        String[] specificStructures = {
                "can", "could", "will", "would", "shall", "should", "may", "might", "must",
                "have to", "need to", "ought to", "used to", "going to",
                "while", "whilst", "when", "where", "whether", "if",
                "a", "an", "the", "this", "that", "these", "those"
        };

        double bonus = 0.0;

        // 检查语法概念匹配
        for (String concept : grammarConcepts) {
            if (query.contains(concept) && question.contains(concept)) {
                bonus += 0.1;
            }
        }

        // 检查用法概念匹配
        for (String concept : usageConcepts) {
            if (query.contains(concept) && question.contains(concept)) {
                bonus += 0.07;
            }
        }

        // 检查具体语法结构匹配 - 这对模态动词等特定问题特别重要
        for (String structure : specificStructures) {
            // 确保我们匹配的是完整单词，而不是部分匹配
            String wordBoundaryPattern = "\\b" + structure + "\\b";
            if (query.matches(".*" + wordBoundaryPattern + ".*") &&
                    question.matches(".*" + wordBoundaryPattern + ".*")) {
                bonus += 0.15; // 这类匹配更重要
            }
        }

        // 特殊情况：比较两个概念的情况给予额外加分
        if ((query.contains("difference") || query.contains("vs") || query.contains("versus") ||
                query.contains("or") || query.contains("between")) &&
                (question.contains("difference") || question.contains("vs") || question.contains("versus") ||
                        question.contains("or") || question.contains("between"))) {
            bonus += 0.15;
        }

        return Math.min(0.4, bonus); // 增加最大加分上限到0.4
    }

    private void analyzeDetailedResults(Map<String, Double> weightedScores, Map<String, Double> directScores,
            PrintWriter logWriter) {
        String detailHeader = "\n======= 详细分析 =======";
        System.out.println(detailHeader);
        logWriter.println(detailHeader);

        int weightedWins = 0;
        int ties = 0;
        int directWins = 0;

        for (String query : testQueries) {
            double weightedScore = weightedScores.getOrDefault(query, 0.0);
            double directScore = directScores.getOrDefault(query, 0.0);
            double diff = weightedScore - directScore;

            String resultLine;
            if (Math.abs(diff) < 0.01) {
                ties++;
                resultLine = "TIE: " + query + " (差异: " + String.format("%.3f", diff) + ")";
            } else if (diff > 0) {
                weightedWins++;
                resultLine = "WIN: " + query + " (提升: " + String.format("%.3f", diff) + ")";
            } else {
                directWins++;
                resultLine = "LOSS: " + query + " (下降: " + String.format("%.3f", diff) + ")";
            }
            System.out.println(resultLine);
            logWriter.println(resultLine);
        }

        String statHeader = "\n统计结果:";
        String winStat = "加权向量化问题获胜: " + weightedWins + " 次";
        String tieStat = "平局: " + ties + " 次";
        String lossStat = "直接向量化问题获胜: " + directWins + " 次";
        String winRate = "胜率: " + String.format("%.1f%%", (double) weightedWins / testQueries.size() * 100);

        System.out.println(statHeader);
        System.out.println(winStat);
        System.out.println(tieStat);
        System.out.println(lossStat);
        System.out.println(winRate);
        logWriter.println(statHeader);
        logWriter.println(winStat);
        logWriter.println(tieStat);
        logWriter.println(lossStat);
        logWriter.println(winRate);
    }

    /**
     * 初始化查询到文档问题的映射
     * 这将帮助我们更好地评估搜索结果与查询的相关性
     */
    private void initializeQueryMapping(Resource resource) {
        try {
            String content = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
            ObjectMapper objectMapper = new ObjectMapper();

            List<Map<String, Object>> qaItems = objectMapper.readValue(
                    content,
                    new TypeReference<List<Map<String, Object>>>() {
                    });

            // 为每个测试查询创建映射
            for (String query : testQueries) {
                List<String> matchingQuestions = new ArrayList<>();
                for (Map<String, Object> qaItem : qaItems) {
                    if (qaItem.containsKey("question")) {
                        String fullQuestion = qaItem.get("question").toString();

                        // 提取第一行作为主问题
                        String[] lines = fullQuestion.split("\\r?\\n");
                        String mainQuestion = lines[0].trim();

                        // 简单地基于关键词匹配，判断问题是否与查询相关
                        if (isQuestionRelevantToQuery(query, mainQuestion, fullQuestion)) {
                            matchingQuestions.add(fullQuestion);
                        }
                    }
                }
                queryToDocumentMap.put(query, matchingQuestions);
            }

            // 日志输出映射信息
            System.out.println("\n=== 查询到文档问题的映射 ===");
            for (String query : testQueries) {
                List<String> questions = queryToDocumentMap.get(query);
                System.out.println("查询: " + query);
                System.out.println("  匹配的问题数: " + questions.size());
                for (int i = 0; i < Math.min(3, questions.size()); i++) { // 只显示前3个
                    System.out.println("  - " + questions.get(i).split("\\r?\\n")[0]);
                }
                if (questions.size() > 3) {
                    System.out.println("  - ...还有 " + (questions.size() - 3) + " 个问题");
                }
            }

        } catch (IOException e) {
            System.err.println("创建查询映射失败: " + e.getMessage());
        }
    }

    /**
     * 判断问题是否与查询相关
     */
    private boolean isQuestionRelevantToQuery(String query, String mainQuestion, String fullQuestion) {
        // 将查询和问题转为小写进行比较
        String queryLower = query.toLowerCase();
        String mainQuestionLower = mainQuestion.toLowerCase();
        String fullQuestionLower = fullQuestion.toLowerCase();

        // 情况1: 查询包含在主问题中
        if (mainQuestionLower.contains(queryLower)) {
            return true;
        }

        // 情况2: 提取查询中的关键词，如果问题包含大部分关键词，则认为相关
        String[] queryWords = queryLower.split("\\s+");
        int matchCount = 0;
        for (String word : queryWords) {
            // 忽略常见停用词
            if (word.length() <= 2 || isStopWord(word)) {
                continue;
            }
            if (fullQuestionLower.contains(word)) {
                matchCount++;
            }
        }

        // 如果匹配率超过60%，认为问题与查询相关
        int significantWords = 0;
        for (String word : queryWords) {
            if (word.length() > 2 && !isStopWord(word)) {
                significantWords++;
            }
        }

        return significantWords > 0 && (double) matchCount / significantWords >= 0.6;
    }

    /**
     * 判断是否为停用词
     */
    private boolean isStopWord(String word) {
        Set<String> stopWords = Set.of("the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for", "of",
                "with", "by", "is", "are", "was", "were", "be", "been", "have", "has", "had", "do", "does", "did",
                "will", "would", "could", "should", "may", "might", "can");
        return stopWords.contains(word);
    }

    /**
     * 计算两个向量之间的余弦相似度
     * 余弦相似度 = (A·B)/(|A|·|B|)
     * 值范围从-1到1，1表示完全相似，0表示无关，-1表示完全相反
     */
    private double calculateCosineSimilarity(List<Double> vector1, List<Double> vector2) {
        if (vector1 == null || vector2 == null || vector1.isEmpty() || vector2.isEmpty()) {
            return 0.0;
        }

        // 确保两个向量维度相同
        if (vector1.size() != vector2.size()) {
            System.err.println("向量维度不匹配，无法计算相似度");
            return 0.0;
        }

        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;

        for (int i = 0; i < vector1.size(); i++) {
            dotProduct += vector1.get(i) * vector2.get(i);
            norm1 += Math.pow(vector1.get(i), 2);
            norm2 += Math.pow(vector2.get(i), 2);
        }

        // 避免除零错误
        if (norm1 == 0 || norm2 == 0) {
            return 0.0;
        }

        // 计算余弦相似度
        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }

    /**
     * 获取查询的向量表示
     * 如果缓存中已存在，则直接返回，否则计算并缓存
     */
    private List<Double> getQueryEmbedding(String query) {
        if (queryEmbeddingsCache.containsKey(query)) {
            return queryEmbeddingsCache.get(query);
        }

        try {
            List<Double> embedding = embeddingClient.embed(query);
            queryEmbeddingsCache.put(query, embedding);
            return embedding;
        } catch (Exception e) {
            System.err.println("计算查询嵌入向量失败: " + e.getMessage());
            return new ArrayList<>();
        }
    }

    /**
     * 直接向量化问题读取器
     * 直接对问题文本进行向量化，不使用加权计算
     */
    public static class DirectQuestionVectorizer {
        private final Resource resource;
        private final EmbeddingClient embeddingClient;
        private final ObjectMapper objectMapper = new ObjectMapper();

        public DirectQuestionVectorizer(Resource resource, EmbeddingClient embeddingClient) {
            this.resource = resource;
            this.embeddingClient = embeddingClient;
        }

        public List<Document> get() {
            try {
                List<Document> documents = new ArrayList<>();
                String content = StreamUtils.copyToString(this.resource.getInputStream(), StandardCharsets.UTF_8);

                List<Map<String, Object>> qaItems = objectMapper.readValue(
                        content,
                        new TypeReference<List<Map<String, Object>>>() {
                        });

                for (Map<String, Object> qaItem : qaItems) {
                    Document doc = processQAPair(qaItem);
                    if (doc != null) {
                        documents.add(doc);
                    }
                }

                return documents;
            } catch (IOException e) {
                throw new RuntimeException("读取问答数据文件失败: " + e.getMessage(), e);
            }
        }

        private Document processQAPair(Map<String, Object> qaItem) {
            // 提取基本信息
            String postId = qaItem.getOrDefault("post_id", "").toString();
            String question = qaItem.getOrDefault("question", "").toString();
            String answer = qaItem.getOrDefault("answer", "").toString();
            Integer score = qaItem.containsKey("score") ? Integer.valueOf(qaItem.get("score").toString()) : 0;

            @SuppressWarnings("unchecked")
            List<String> tags = qaItem.containsKey("tags") ? (List<String>) qaItem.get("tags") : new ArrayList<>();

            Integer answerCount = qaItem.containsKey("answer_count")
                    ? Integer.valueOf(qaItem.get("answer_count").toString())
                    : 0;

            @SuppressWarnings("unchecked")
            List<String> allAnswers = qaItem.containsKey("all_answers") ? (List<String>) qaItem.get("all_answers")
                    : new ArrayList<>();

            // 如果问题为空，跳过
            if (question.isEmpty()) {
                return null;
            }

            // 提取问题的第一行作为主要问题
            String[] lines = question.split("\\r?\\n");
            String mainQuestion = lines[0].trim();

            // 直接对问题文本进行向量化，不做任何加权处理
            List<Double> embedding;
            try {
                embedding = embeddingClient.embed(question);
            } catch (Exception e) {
                System.err.println("计算问题嵌入向量失败: " + e.getMessage());
                return null;
            }

            // 构建元数据
            Map<String, Object> metadata = new HashMap<>();
            metadata.put("post_id", postId);
            metadata.put("score", score);
            metadata.put("question", question); // 保存完整问题
            metadata.put("main_question", mainQuestion); // 保存主要问题
            metadata.put("answer", answer);
            metadata.put("tags", tags);
            metadata.put("answer_count", answerCount);
            metadata.put("all_answers", allAnswers);
            metadata.put("embedding", embedding);

            // 创建Document对象 - 使用完整问题内容作为文档内容
            String id = UUID.randomUUID().toString();
            return new Document(id, question, metadata);
        }
    }
}
